﻿using Android.App;
using Android.Bluetooth;
using Android.Content;
using Android.OS;
using Android.Util;
using Java.Util;
using nhCore;
using nhCore.Modbus.Frame;
using nhCore.Modbus;
using System.Collections.Generic;
using System.Linq;
using Intent = Android.Content.Intent;
using Newtonsoft.Json;
using Service = Android.App.Service;
using WSYmi.MainAct;
using static Android.Bluetooth.BluetoothClass;
using Android.Widget;
using Java.Lang;
using Java.Util.Logging;
using Android.Media;
using System;
using AndroidX.Core.App;
using static Android.OS.PowerManager;
using static Android.Telephony.CarrierConfigManager;
using Xamarin.Essentials;
using AndroidX.LocalBroadcastManager.Content;

namespace WSYmi.BleService
{
    [Service]
    public class BleService : Service
    {
        static string TAG { get; } = typeof(BleService).FullName;

        //蓝牙相关类
        private BluetoothManager BluetoothManager { get; set; }

        private BluetoothAdapter BluetoothAdapter { get; set; }

        internal BluetoothGatt BluetoothGatt { get; set; }

        private BluetoothGattCharacteristic Characteristic { get; set; }

        private BleGattCallback BluetoothGattCallback { get; set; }

        /// <summary>
        /// 为flase时停止对应task
        /// </summary>
        public bool IsRunning { get; set; } = true;

        private bool IsStarted { get; set; }

        /// <summary>
        /// 本连接下的命令列表
        /// </summary>
        public List<Cmd> Cmds { get; set; } = new List<Cmd>();

        /// <summary>
        /// 返回数据
        /// </summary>
        private object ORead;

        /// <summary>
        /// 正在通讯的设备序号
        /// </summary>
        internal string DeviceSn { get; set; }

        /// <summary>
        /// 互斥体，等待接受数据
        /// </summary>
        private readonly System.Threading.AutoResetEvent AreWait = new System.Threading.AutoResetEvent(false);

        /// <summary>
        /// 最大记录次数
        /// </summary>
        private int RecordCountMax { get; set; }

        /// <summary>
        /// 记录次数
        /// </summary>
        private int RecordCount { get; set; }

        /// <summary>
        /// 最近读到的气象要素
        /// </summary>
        private Weathers Weathers { get; set; }

        /// <summary>
        /// 定时器，记录用
        /// </summary>
        private System.Timers.Timer Timer { get; set; } = new System.Timers.Timer();

        private string RecordFileName { get; set; }

        public const string ACTION_Server = "com.nengh.WSYmi.BleService";
        public const string KEY_State = "KEY_State";
        public const string KEY_Message = "KEY_Message";
        public const string KEY_DeviceSn = "KEY_DeviceSn";
        public const string KEY_Weather = "KEY_Weather";

        static readonly string CHANNEL_ID = "location_notification";

        /// <summary>
        /// 蓝牙设备是否连接
        /// </summary>
        internal bool IsBleConn { get; set; }

        private PowerManager.WakeLock WakeLock { get; set; }

        #region 前台服务
        /// <summary>
        /// 每次服务启动时调用，可能被系统重复调用
        /// </summary>
        /// <param name="intent">启动组件传递过来的Intent</param>
        /// <param name="flags"></param>
        /// <param name="startId">指明当前服务的唯一ID</param>
        /// <returns></returns>
        public override StartCommandResult OnStartCommand(Intent intent, StartCommandFlags flags, int startId)
        {
            if (intent.Action.Equals(Constants.ACTION_START_SERVICE))
            {
                if (IsStarted)
                {
                    Log.Debug(TAG, "OnStartCommand: 服务已经启动。");
                }
                else
                {
                    Log.Debug(TAG, "OnStartCommand: 启动服务。");
                    RegisterForegroundService();
                    //handler.PostDelayed(runnable, Constants.DELAY_BETWEEN_LOG_MESSAGES);
                    IsStarted = true;
                }
            }
            else if (intent.Action.Equals(Constants.ACTION_STOP_RECORD))
            {
                Log.Debug(TAG, "OnStartCommand: 停止记录。");
                BluetoothGatt.Disconnect();
                BroadcastUpdate("停止记录，断开蓝牙设备。");
                RecordStop();
            }
            else if (intent.Action.Equals(Constants.ACTION_RESTART_TIMER))
            {
                Log.Debug(TAG, "OnStartCommand: 重启服务");
                //timestamper.Restart();

            }
            return StartCommandResult.Sticky; //告知 Android 重启服务，但不提供启动服务的最后一个意向
        }

        void RegisterForegroundService()
        {
            CreateNotificationChannel();
            Notification notification = new Notification.Builder(this, CHANNEL_ID)
                .SetContentTitle("正在记录...")
                .SetContentText($"点击跳转到->{Resources.GetString(Resource.String.app_name)}。")
                .SetSmallIcon(Resource.Drawable.ic_tz)
                .SetContentIntent(BuildIntentToShowMainActivity())
                .SetOngoing(true)       //持续通知
                                        //.AddAction(BuildRestartTimerAction())
                .AddAction(BuildStopRecordAction())
                .Build();

            // Enlist this instance of the service as a foreground service
            StartForeground(Constants.SERVICE_RUNNING_NOTIFICATION_ID, notification);
        }

        void CreateNotificationChannel()
        {
            if (Build.VERSION.SdkInt < BuildVersionCodes.O)
            {
                // Notification channels are new in API 26 (and not a part of the
                // support library). There is no need to create a notification
                // channel on older versions of Android.
                return;
            }

            var channel = new NotificationChannel(CHANNEL_ID, "保存通知", NotificationImportance.High)
            {
                Description = "环境数据保存数量及倒计时通知。"
            };

            var notificationManager = (NotificationManager)GetSystemService(NotificationService);
            notificationManager.CreateNotificationChannel(channel);
        }

        /// <summary>
        /// 构建一个PendingIntent，它将显示应用程序的主要活动。当用户点击通知；它将带他们进入应用程序的主要活动。
        /// </summary>
        /// <returns>The content intent.</returns>
        PendingIntent BuildIntentToShowMainActivity()
        {
            Intent notificationIntent = new Intent(this, typeof(MainActivity));
            notificationIntent.SetAction(Constants.ACTION_MAIN_ACTIVITY);
            notificationIntent.SetFlags(ActivityFlags.SingleTop);
            notificationIntent.PutExtra(Constants.SERVICE_STARTED_KEY, true);
            PendingIntent pendingIntent;
            if (Build.VERSION.SdkInt >= BuildVersionCodes.S)
            {
                pendingIntent = PendingIntent.GetActivity(this, 0, notificationIntent, PendingIntentFlags.Mutable);
            }
            else
            {
                pendingIntent = PendingIntent.GetActivity(this, 0, notificationIntent, PendingIntentFlags.UpdateCurrent);
            }
            return pendingIntent;
        }

        /// <summary>
        /// Builds a Notification.Action that will instruct the service to restart the timer.
        /// </summary>
        /// <returns>The restart timer action.</returns>
        Notification.Action BuildRestartTimerAction()
        {
            var restartTimerIntent = new Intent(this, GetType());
            restartTimerIntent.SetAction(Constants.ACTION_RESTART_TIMER);
            PendingIntent restartTimerPendingIntent;
            if (Build.VERSION.SdkInt >= BuildVersionCodes.S)
            {
                restartTimerPendingIntent = PendingIntent.GetService(this, 0, restartTimerIntent, PendingIntentFlags.Immutable);
            }
            else
            {
                restartTimerPendingIntent = PendingIntent.GetService(this, 0, restartTimerIntent, 0);
            }
            var builder = new Notification.Action.Builder(Resource.Drawable.notification_template_icon_low_bg,
                                              "重新开始",
                                              restartTimerPendingIntent);

            return builder.Build();
        }

        /// <summary>
        /// 生成通知，生成通知。允许用户通过状态栏中的通知停止服务的操作
        /// </summary>
        /// <returns>The stop service action.</returns>
        Notification.Action BuildStopRecordAction()
        {
            var stopServiceIntent = new Intent(this, GetType());
            stopServiceIntent.SetAction(Constants.ACTION_STOP_RECORD);
            PendingIntent stopServicePendingIntent;
            if (Build.VERSION.SdkInt >= BuildVersionCodes.S)
            {
                stopServicePendingIntent = PendingIntent.GetService(this, 0, stopServiceIntent, PendingIntentFlags.Immutable);
            }
            else
            {
                stopServicePendingIntent = PendingIntent.GetService(this, 0, stopServiceIntent, 0);
            }
            var builder = new Notification.Action.Builder(Android.Resource.Drawable.IcMediaPause,
                                                          "停止记录",
                                                          stopServicePendingIntent);
            return builder.Build();
        }
        #endregion

        /// <summary>
        /// 初始化蓝牙接口、蓝牙回调，传递监听
        /// </summary>
        /// <param name="svrListener"></param>
        /// <returns></returns>
        public bool Initialize()
        {
            if (BluetoothManager == null)
            {   //获取系统的蓝牙管理器
                BluetoothManager = (BluetoothManager)GetSystemService(Context.BluetoothService);
                if (BluetoothManager == null)
                {
                    Log.Debug(TAG, "未能初始化BluetoothManager。");
                    return false;
                }
            }

            BluetoothAdapter = BluetoothManager.Adapter;
            if (BluetoothAdapter == null)
            {
                Log.Debug(TAG, "未能获得BluetoothAdapter.");
                return false;
            }

            BluetoothGattCallback = new BleGattCallback(this);

            Timer.Elapsed += new System.Timers.ElapsedEventHandler(OnTimer);//到达时间的时候执行事件；
            Timer.AutoReset = true;//设置是执行一次（false）还是一直执行(true)；

            return true;
        }

        /// <summary>
        /// 连接蓝牙设备
        /// </summary>
        /// <param name="device">蓝牙设备</param>
        /// <returns></returns>
        public bool Connect(string address)
        {
            if (address == null)
            {
                Log.Debug(TAG, "蓝牙设备没有发现，不能连接。");
                return false;
            }

            //获取远端的蓝牙设备
            BluetoothDevice device = BluetoothAdapter?.GetRemoteDevice(address);

            if (BluetoothAdapter == null || device == null)
            {
                Log.Debug(TAG, "BluetoothAdapter未初始化或未指明地址.");
                return false;
            }

            BluetoothGatt = device.ConnectGatt(this, false, BluetoothGattCallback);
            return true;
        }

        private void CmdTask()
        {
            Cmd TmpCmd = null; //当前命令
            int sleepTime = 0;

            while (IsRunning)
            {
                if (Cmds.Count > 0)
                {
                    TmpCmd = Cmds?.OrderBy(x => x.Time).First();//没设备时会为空
                    sleepTime = (int)(TmpCmd.Time - System.DateTime.Now).TotalMilliseconds;//计算最近命令休眠相应时间
                }
                else
                {
                    sleepTime = 1000;//无命令时休眠1s
                }

                if (Cmds.Count > 0 && sleepTime <= 0) //立即发送
                {
                    byte[] data = (byte[])TmpCmd.SentCmd.GetCmd();
                    TmpCmd.RefreshTime();
                    Log.Debug(TAG, $"{TmpCmd.SentCmd}下一条{TmpCmd.SentCmd.DelayTime}ms");
                    ORead = null;
                    Characteristic.SetValue(data);
                    bool status = BluetoothGatt.WriteCharacteristic(Characteristic);

                    AreWait.WaitOne(1000);

                    if (ORead != null || TmpCmd.SentCmd.IsAnswer(ORead))//效验通过，功能码、地址符合
                    {
                        TmpCmd.SentCmd.SleepState = false;
                        TmpCmd.FailedCount = 0;
                        object o = TmpCmd.SentCmd.Analyzer.Analysis(ORead);//解析

                        DataResult(o, TmpCmd);
                        TmpCmd.SentCmd.NextCmd();//实时类用继承基类的空方法

                        TmpCmd.IsDelete = !TmpCmd.SentCmd.Automatic;
                    }
                    else
                    {   //无回复或回复异常
                        TmpCmd.FailedCount++;

                        if (TmpCmd.FailedCount >= 3)
                        {
                            if (TmpCmd.SentCmd.Automatic)
                            {
                                TmpCmd.SentCmd.SleepState = true;//自动命令进入SleepState
                            }
                            else
                            {
                                TmpCmd.IsDelete = true;
                                //MsgListener.Error($"{ClientAddress}接口中 <{TmpCmd.SentCmd.Key}> {TmpCmd.FailedCount}次失败，不再发送");
                            }
                        }
                    }

                    if (TmpCmd.IsDelete) //非Auto命令发送3次失败或任务完成即删除
                    {
                        _ = Cmds.Remove(TmpCmd);
                    }
                }
                else
                {   //休眠
                    Java.Lang.Thread.Sleep(sleepTime);
                }
            }
        }

        /// <summary>
        /// 收到数据处理
        /// </summary>
        /// <param name="values"></param>
        /// <param name="cmd"></param>
        public void DataResult(object values, Cmd cmd)
        {
            if (cmd.SentCmd is ReadSnCmd)
            {
                DeviceSn = (values as string).Remove(0, 3);
                BroadcastUpdate(KEY_DeviceSn, DeviceSn);
                Log.Debug(TAG, DeviceSn);
            }
            else if (cmd.SentCmd is RealTimeCmd)
            {
                Weathers = (Weathers)values;
                BroadcastUpdate(Weathers);
                Log.Debug(TAG, Weathers.ToExtString());
            }
        }

        #region 数据记录
        /// <summary>
        /// 开始记录
        /// </summary>
        /// <param name="fileName">文件名</param>
        /// <param name="intrvalMs">记录间隔，毫秒</param>
        /// <param name="recordSec">记录总时间，秒</param>
        /// <returns>true文件建立成功</returns>
        public bool RecordStart(string fileName, int intrvalMs, int recordSec = -1)
        {
            RecordFileName = fileName;
            Cmd cmd = Cmds.Find(c => c.SentCmd.Code == 4);
            bool ret = false;
            if (cmd == null)
            {
                Log.Debug(TAG, " Cmds.Find()为空。");
                return ret;
            }

            //组标题
            string titel = "";
            foreach (var d in cmd.SentCmd.Analyzer.Decoders.OrderBy((x) => x.Config.Index))
            {
                if (d.Config.Index == 3) continue;//电池跳过
                titel += d.Config.Display + (string.IsNullOrWhiteSpace(d.Config.Unit) ? "," : $"({d.Config.Unit}),");
            }
            titel += DeviceSn;

            try
            {
                FileData.CreateTextAsync(fileName, titel); //建立文件，保存标题
                ret = true;
                cmd.SetDelayTime(intrvalMs > 5000 ? 5000 : intrvalMs);
                //cmd.SetDelayTime(1000);
                RecordCountMax = recordSec >= 0 ? recordSec * 1000 / intrvalMs : -1;
                RecordCount = 0;
                Timer.Interval = intrvalMs;
                OnTimer(this, null); //立即执行一次
                Timer.Start(); //启动定时器

                PowerManager pm = (PowerManager)GetSystemService(Context.PowerService);// 获取PowerManager对象
                WakeLock = pm.NewWakeLock(WakeLockFlags.Partial, TAG);// 创建WakeLock锁实例
                WakeLock.SetReferenceCounted(false);
                if (recordSec >= 0)
                {
                    WakeLock.Acquire(recordSec * 1000);// 申请WakeLock
                }
                else
                {
                    WakeLock.Acquire();// 申请WakeLock
                }
            }
            catch (System.Exception)
            {
                string msg = $"建立文件[{fileName}]失败！";
                BroadcastUpdate(msg);
                Log.Debug(TAG, msg);
            }

            return ret;
        }

        /// <summary>
        /// 停止记录
        /// </summary>
        public void RecordStop()
        {
            Cmd cmd = Cmds.Find(c => c.SentCmd.Code == 4);
            cmd?.SetDelayTime(3000);
            Timer.Stop();

            StopForeground(true);
            StopSelf();
            IsStarted = false;

            if (WakeLock != null)
            {
                WakeLock.Release();// 释放WakeLock
                WakeLock = null;
            }
        }

        /// <summary>
        /// 定时保存数据
        /// </summary>
        /// <param name="source"></param>
        /// <param name="e"></param>
        /// <exception cref="NotImplementedException"></exception>
        private void OnTimer(object source, System.Timers.ElapsedEventArgs e)
        {
            if (Weathers != null)
            {
                string time = Weathers?.Values[-1].StrValueUnit;
                FileData.AppendTextAsync(RecordFileName, $"{time},{Weathers?.Values[4].StrValue}," +
                    $"{Weathers?.Values[5].StrValue},{Weathers?.Values[6].StrValue}");
            }

            RecordCount++;
            string tz = $"已记录{RecordCount}条。";
            if (RecordCountMax > 0)//设置了记录时间，可自动停止
            {
                if (RecordCount >= RecordCountMax)
                {
                    Timer.Stop();
                    string str = "记录完成，断开蓝牙设备。";
                    BroadcastUpdate(str);
                    Log.Debug(TAG, str);
                    tz += str;
                    BluetoothGatt.Disconnect();
                    //BluetoothGatt.Close();
                    //提示记录完成
                    StopForeground(true);
                    StopSelf();
                    IsStarted = false;
                }
                else
                {
                    int 剩余条数 = RecordCountMax - RecordCount;
                    TimeSpan timeSpan = new TimeSpan((long)(Timer.Interval * 10000 * 剩余条数));
                    tz += $"还剩{剩余条数}条，{timeSpan}后完成";
                }
            }
            else //未设置记录时间
            {
                TimeSpan timeSpan = new TimeSpan((long)(Timer.Interval * 10000 * (RecordCount - 1)));
                tz += $"已工作{timeSpan}。";
            }

            Notification notification = new NotificationCompat.Builder(this, CHANNEL_ID)
                    .SetContentTitle("记录通知")
                    .SetContentText(tz)
                    .SetSmallIcon(Resource.Drawable.ic_tz)
                    .SetVisibility((int)NotificationVisibility.Public)  //可在锁屏界面显示内容
                    .SetCategory(Notification.CategoryProgress)         //分类：后台进度
                    .SetDefaults((int)NotificationDefaults.All)         //有声音和震动
                    .SetContentIntent(BuildIntentToShowMainActivity())
                    .Build();

            NotificationManager notificationManager =
                GetSystemService(Context.NotificationService) as NotificationManager;

            const int notificationId = 9997;
            notificationManager.Notify(notificationId, notification);
        }
        #endregion

        #region 蓝牙回调的回调
        /// <summary>
        /// 蓝牙连接成功
        /// </summary>
        /// <param name="gatt"></param>
        /// <param name="bluetoothGattService"></param>
        /// <param name="characteristic"></param>
        public void Connected(BluetoothGatt gatt, BluetoothGattService bluetoothGattService, BluetoothGattCharacteristic characteristic)
        {
            SetCharacteristicNotification(gatt, characteristic, true);

            Characteristic = characteristic;
            IsRunning = true;

            Java.Lang.Thread.Sleep(100);
            new Java.Lang.Thread(CmdTask).Start();
        }

        /// <summary>
        /// 设置特征值通变化通知
        /// </summary>
        /// <param name="characteristic">特征值</param>
        /// <param name="enabled">使能</param>
        public void SetCharacteristicNotification(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic, bool enabled)
        {
            gatt.SetCharacteristicNotification(characteristic, enabled);

            BluetoothGattDescriptor descriptor = characteristic.GetDescriptor(
                UUID.FromString("00002902-0000-1000-8000-00805f9b34fb"));

            if (enabled)
            {
                descriptor.SetValue(BluetoothGattDescriptor.EnableNotificationValue.ToArray());
            }
            else
            {
                descriptor.SetValue(BluetoothGattDescriptor.DisableNotificationValue.ToArray());
            }
            gatt.WriteDescriptor(descriptor);
        }

        /// <summary>
        /// 收到设备数据
        /// </summary>
        /// <param name="gatt"></param>
        /// <param name="characteristic"></param>
        /// <exception cref="NotImplementedException"></exception>
        public void OnCharacteristicChanged(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic)
        {
            ORead = characteristic.GetValue();
            AreWait.Set();//通知互斥体继续
        }
        #endregion

        #region 广播意图
        public void BroadcastUpdate(string key, string value)
        {
            Intent message = new Intent(ACTION_Server);
            message.PutExtra(key, value);
            AndroidX.LocalBroadcastManager.Content.LocalBroadcastManager.GetInstance(this).SendBroadcast(message);
        }

        /// <summary>
        /// 广播状态
        /// </summary>
        /// <param name="key"></param>
        /// <param name="value"></param>
        public void BroadcastUpdate(string key, int value)
        {
            Intent message = new Intent(ACTION_Server);
            message.PutExtra(key, value);
            AndroidX.LocalBroadcastManager.Content.LocalBroadcastManager.GetInstance(this).SendBroadcast(message);
        }

        /// <summary>
        /// 广播消息
        /// </summary>
        /// <param name="message"></param>
        public void BroadcastUpdate(string message)
        {
            BroadcastUpdate(KEY_Message, message);
        }

        /* 广播远程发送过来的数据 */
        public void BroadcastUpdate(Weathers weathers)
        {
            if (weathers != null)
            {
                BroadcastUpdate(KEY_Weather, JsonConvert.SerializeObject(weathers));
            }
        }
        #endregion

        #region 实现Android Binder
        public IBinder Binder { get; private set; }

        /// <summary>
        /// 当第一个客户端尝试连接到服务时，将调用它，实例IBinder ，以便客户端可以与服务交互
        /// </summary>
        /// <param name="intent"></param>
        /// <returns></returns>
        public override IBinder OnBind(Intent intent)
        {
            Binder = new BleBinder(this);
            return Binder;
        }

        public override bool OnUnbind(Intent intent)
        {
            return base.OnUnbind(intent);
        }
        #endregion

        public override void OnDestroy()
        {
            IsRunning = false;
            Binder = null;
            Timer.Stop();
            Timer.Dispose();
            if ((bool)(WakeLock?.IsHeld))
            {
                WakeLock.Release();
            }
            base.OnDestroy();
        }
    }
}